package com.ysd.util;

import java.util.UUID;

/**
* 根据时间戳获取唯一值
*该方法使用了类似于Twitter的Snowflake算法，将时间戳和序列号组合生成唯一的long类型数值。其中，起始时间戳为START_TIMESTAMP，序列号位数为SEQUENCE_BITS，最大序列号为MAX_SEQUENCE。lastTimestamp表示上次生成ID的时间戳，sequence表示当前序列号。
*调用generateUniqueId()方法即可获取一个唯一的long类型数值。
 * @author Bai
 * @since 2023-10-08
* */
public class UniqueIdGenerator {
    private static final long START_TIMESTAMP = 1633754921102L; // 设置起始时间戳，用于计算当前时间戳相对于起始时间戳的差值
    private static final long SEQUENCE_BITS = 12L; // 序列号位数
    private static final long MAX_SEQUENCE = (1L << SEQUENCE_BITS) - 1; // 最大序列号
    private static long lastTimestamp = -1L; // 上次生成ID的时间戳
    private static long sequence = 0L; // 当前序列号

    /**
     * 根据当前时间戳生成唯一的long类型数值
     * @return 唯一的long类型数值
     */
    public synchronized static long generateUniqueId() {
        long currentTimestamp = System.currentTimeMillis();
        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards");
        }

        // 如果当前时间戳与上次生成ID的时间戳相同，则增加序列号
        if (currentTimestamp == lastTimestamp) {
            sequence = (sequence + 1) & MAX_SEQUENCE;
            if (sequence == 0) {
                currentTimestamp = getNextTimestamp(currentTimestamp);
            }
        } else { // 如果当前时间戳比上次生成ID的时间戳大，则重置序列号
            sequence = 0L;
        }

        lastTimestamp = currentTimestamp;

        // 计算ID值并返回
        long timestampDiff = currentTimestamp - START_TIMESTAMP;
        return (timestampDiff << SEQUENCE_BITS) | sequence;
    }

    /**
     * 获取下一个时间戳
     * @param currentTimestamp 当前时间戳
     * @return 下一个时间戳
     */
    private static long getNextTimestamp(long currentTimestamp) {
        long nextTimestamp = System.currentTimeMillis();
        while (nextTimestamp == currentTimestamp) {
            nextTimestamp = System.currentTimeMillis();
        }
        return nextTimestamp;
    }

    public static String generateUniqueIdString(int length) {
        StringBuilder sb = new StringBuilder(length);
        while (sb.length() < length) {
            UUID uuid = UUID.randomUUID();
            String str = uuid.toString().replace("-", "").substring(0, length);
            if (!sb.toString().contains(str)) {
                sb.append(str);
            }
        }
        return sb.toString().substring(0, length);
    }




}

